#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<sys/select.h>

#define SERVERPORT 8000
#define BUFSIZE 1024

int createsock(int port)
{
    int lfd=socket(AF_INET,SOCK_STREAM,0);
    if(lfd==-1)
    {
        perror("socket error");
        exit(1);
    }
    struct sockaddr_in serveraddr;
    serveraddr.sin_family=AF_INET;
    serveraddr.sin_port=htons(SERVERPORT);
    serveraddr.sin_addr.s_addr=0;//任意ip
    //绑定ip和端口号
    bind(lfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr));
    //主动套接字转被动套接字
    listen(lfd,64);
    return lfd;
}

void printSet(fd_set my_set,int nfds)
{
    for(int i=0;i<nfds;i++)
    {
        if(FD_ISSET(i,&my_set))
        {
            printf("1");
        }
        else
        {
            printf("0");
        }
    }
    printf("\n");
}

int main(int argc, char* argv[])
{
    int lfd=createsock(SERVERPORT);
    char buf[BUFSIZE];

    int nfds=-1;
    fd_set read_set,all_set;
    //初始化数组
    FD_ZERO(&all_set);
    //将lfd放入数组中
    FD_SET(lfd,&all_set);
    nfds=lfd+1;

    int selectRet;
    while(1)
    {
        //生成all_set的副本
        read_set=all_set;
        //将lfd交给select监听、
        selectRet=select(nfds,&read_set,NULL,NULL,NULL);
        if(selectRet==-1)
        {
            perror("select error");
            exit(1);
        }
        printf("selectRet = %d\n",selectRet);//打印触发事件的文件描述符总和
        printSet(read_set,nfds);//打印read_set二进制数组的数据

        if(FD_ISSET(lfd,&read_set))
        {
            printf("事件触发马上处理\n");
            int cfd=accept(lfd,NULL,NULL);
            if(cfd==-1)
            {
                perror("accept error");
                exit(1);
            }
            if(cfd>1023)
            {
                printf("too many client\n");
                exit(1);
            }
            //把cfd放入数组中，交给select监听
            FD_SET(cfd,&all_set);
            //更新nfds
            if(cfd>nfds-1)
            {
                nfds=cfd+1;
            }
            if(--selectRet==0)
            {
                continue;
            }
        }
        //对通信套接字的监听
        for(int i=lfd+1;i<nfds;i++)
        {
            if(FD_ISSET(i,&read_set))
            {
                int read_count=read(i,buf,BUFSIZ);
                if(read_count==-1)
                {
                    perror("read error");
                    exit(1);
                }
                else if(read_count==0)
                {
                    printf("有客户端退出\n");
                    close(i);//关闭文件吗描述符
                    FD_CLR(i,&all_set);//将文件描述符从数组中移除
                }
                else
                {
                    write(i,buf,read_count);
                    printf("********************************\n");
                    write(STDOUT_FILENO,buf,read_count);
                    printf("********************************\n");
                }
                if(--selectRet==0)
                {
                    break;
                }
            }
        }
    }
    return 0;
}


